import * as THREE from 'three'
import Viewer from "./Viewer"

// 添加形状类型枚举
export enum ObjectType {
  Cube = 'Cube',
  Sphere = 'Sphere',
  Cylinder = 'Cylinder',
  Cone = 'Cone',
  Torus = 'Torus',
  TorusKnot = 'TorusKnot',
  Plane = 'Plane',
  Box = 'Box',
  Circle = 'Circle',
  Arrow = 'Arrow',
  Arc = 'Arc',
  Line = 'Line',
  Rect = 'Rect',
  Ellipse = 'Ellipse',
  Polygon = 'Polygon',
  Text = 'Text',
  Sprite = 'Sprite',
  Point = 'Point',
  Line2 = 'Line2',
  Line3D = 'Line3D',
  LineStrip = 'LineStrip',
  LineLoop = 'LineLoop',
  Polyline = 'Polyline',
  Polyline3D = 'Polyline3D',
  AddIcon = 'AddIcon'
}

export default class ObjectGenerator extends THREE.EventDispatcher<any> {
  declare view: Viewer
  constructor(view: Viewer) {
    super()
    this.view = view
  }
  init() {
    this.addEventListener('add', data => {
      const { type } = data

      const obj = this[type]()

      this.dispatchEvent({ type: 'added', data: { obj } })
    })
    this.addEventListener('delete', data => {
      this.view.scene.remove(data)
      this.dispatchEvent('deleted')
    })
  }
  AddIcon(point?: THREE.Vector3) {
    const geometry = new THREE.BoxGeometry(1.5, 0.15, 0.15)
    const material = new THREE.MeshBasicMaterial({ color: '#ccc' })

    const h = new THREE.Mesh(geometry, material)
    const v = new THREE.Mesh(geometry, material)
    v.rotation.y = Math.PI / 2
    h.add(v)
    if (point) h.position.copy(point)
    h.userData = { dir: new THREE.Vector3(0, 0, 1) }

    this.view.scene.add(h)
    return h
  }
  [ObjectType.Line](start: THREE.Vector3 | THREE.Vector2, end: THREE.Vector3 | THREE.Vector2) {
    if (
      (start instanceof THREE.Vector2 && end instanceof THREE.Vector3) ||
      (start instanceof THREE.Vector3 && end instanceof THREE.Vector2)
    )
      throw new Error('start and end must be of the same type')
    const material = new THREE.LineDashedMaterial({ color: '#ccc', dashSize: 0.3, gapSize: 0.3, scale: 1 })
    const geometry = new THREE.BufferGeometry().setFromPoints([start, end] as THREE.Vector3[] | THREE.Vector2[])
    const line = new THREE.LineSegments(geometry, material)
    line.computeLineDistances()

    this.view.scene.add(line)
    return line
  }
  [ObjectType.Cube]() {
    const mesh = new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial())
    this.view.scene.add(mesh)

    return mesh
  }
}